const jsonInput = {
  name: 'JsonInput',
  props: {
    maxDepth: {
      type: Number,
      default: 6 // 默认最大递归深度为6
    },
    depth: {
      type: Number,
      default: 1
    },
    commit: {},
    fields: {type: Object, default: {}},
    title: {type: String, default: "标题"},
    isNode: {type: Boolean, default: true},
    noDeleteBtn: {type: Array, default: ['name', 'code', 'componentId']},
    value: {type: Object, default: {name: "名称"}}
  },
  watch: {
    value(newVal) {
      this.hasDataDo()
      this.orderedFieldsDo()
    }
  },
  data() {
    return {
      dialogTitle: '',
      updateFieldFlag: false,
      updateKey: '',
      updateData: {},
      addFieldFlag: false,
      addFields: [],
      fieldOrders: [],
      // key长度
      keyWidth: 0,
      keyWidthSize: [3, 6, 8, 10, 16],
      valInfos: {},
      hasDataFlag: false
    };
  },
  computed: {
    orderedFields() {
      return this.orderedFieldsDo()
    },
  },
  methods: {
    hasDataDo() {
      if (!this.value) {
        this.value = {...this.value};
      }
      this.hasDataFlag = Object.keys(this.value).length > 0;
      return this.hasDataFlag;
    },
    orderedFieldsDo() {
      if (!this.value) {
        this.value = {...this.value};
      }
      const internalValue = this.value;
      this.fieldOrders = [...new Set([...this.fieldOrders.filter(field => internalValue.hasOwnProperty(field)), ...Object.keys(internalValue)])];

      // 设置key的宽度
      let sizeMax = 4
      this.fieldOrders.forEach(key => {
        sizeMax = Math.max(sizeMax, getStrLength(key))
        setValInfos(key, this.valInfos, internalValue)
        this.setEditFlag(key)
        if (this.depth >= this.maxDepth) {
          this.valInfos[key].display = false
        }
      })

      // 设置key type
      // console.log('size max', sizeMax)
      for (let index = 0; index < this.keyWidthSize.length; index++) {
        if (index === this.keyWidthSize.length - 1) {
          this.keyWidth = index
          break
        }
        if (this.keyWidthSize[index] < sizeMax && sizeMax <= this.keyWidthSize[index + 1]) {
          this.keyWidth = index
          break
        }
      }
      return this.fieldOrders
    },
    setEditFlag(field) {
      this.valInfos[field].editFlag = this.valInfos[field].jsonStr || this.valInfos[field].type === 'object'
        || (!this.valInfos[field].display && (this.valInfos[field].jsonStr || this.valInfos[field].type === 'object'))
    },
    updateValue() {
      this.$emit('input', this.value); // 通知父组件数据变化
    },
    setBooleanValue(key, val) {
      this.value[key] = val
    },
    toStr(key) {
      this.valInfos[key].type = 'string'
      this.valInfos[key].jsonStr = true
      this.value[key] = jsonToStr(this.value[key])
    },
    toJson(key) {
      this.valInfos[key].jsonStr = false
      this.value[key] = strToJson(this.value[key])
      this.valInfos[key].type = typeof this.value[key]
    },
    objToStr(val) {
      if (typeof val === 'object') {
        return JSON.stringify(val)
      } else {
        return val
      }
    },
    deleteField(key) {
      this.$confirm(`确认删除 ${key} 字段?`, 'warning')
        .then( () => {
          if (Array.isArray(this.value)) {
            this.value.splice(key, 1);
          } else {
            delete this.value[key];
          }
          this.refreshValue()
          this.$message.success(`删除 ${key} 字段成功。`)
        })
    },
    copyValue(value) {
      copyTextIn(value);
      this.$message.success('复制 ' + value + ' 成功。')
    },
    copyObj(value, isSpace) {
      if (typeof value === 'string') {
        this.$message.success('复制 ' + copyTextIn(value) + ' 成功。')
        return
      }
      if (!isSpace) {
        this.$message.success('复制 ' + copyTextIn(JSON.stringify(value)) + ' 成功。')
        return
      }
      this.$message.success('复制 ' + copyTextIn(jsonToStrFormat(value)) + ' 成功。')
    },
    setDisplay(field, val) {
      this.$set(this.valInfos[field], 'display', val);
      this.setEditFlag(field)
      this.resetJsonDisplay()
    },
    setJsonDisplay(val) {
      if (Array.isArray(this.$refs.child)) {
        this.$refs.child.forEach(child => {
          child.setJsonDisplay(val)
        })
      } else if (this.$refs.child) {
        this.$refs.child.setJsonDisPlay(this.childrenJsonDisplay)
      }
      resetValInfos(this.valInfos, val)
      this.resetJsonDisplay()
    },
    resetJsonDisplay() {
      let info = {...this.valInfos}
      this.valInfos = {}
      this.valInfos = info
    },
    resetStr(key) {
      if (strIsJson(this.value[key])) {
        this.valInfos[key].jsonStr = true
      } else {
        this.valInfos[key].jsonStr = false
      }
      this.$emit('input', this.value);
    },
    // 对象编辑
    updateStrObj(key) {
      this.dialogTitle = `第${this.depth}层的《${key}》 json字符串修改`
      this.updateKey = key
      if (typeof this.value[key] === 'string') {
        this.updateData = strToJson(this.value[key])
      } else {
        this.updateData = this.value[key]
      }
      this.updateFieldFlag = true
    },
    updateFieldDo() {
      this.value[this.updateKey] = this.updateData
      this.updateFieldFlag = false
    },
    addField() {
      this.addFields.push({fieldKey: '', fieldType: 'string', fieldValue: ''})
      if (Array.isArray(this.value)) {
        this.addFields[this.addFields.length - 1].fieldKey = this.value.length + this.addFields.length - 1
      }
      this.addFieldFlag = true
    },
    addFieldDo() {
      for (let item of this.addFields) {
        if ((!item.fieldKey && item.fieldKey !== 0) || !item.fieldType) {
          continue
        }
        if (item.fieldType === 'string') {
          this.value[item.fieldKey] = item.fieldValue
        } else if (item.fieldType === 'number') {
          this.value[item.fieldKey] = parseFloat(item.fieldValue)
        } else if (item.fieldType === 'boolean') {
          this.value[item.fieldKey] = item.fieldValue === 'true'
        } else if (item.fieldType === 'array') {
          try {
            this.value[item.fieldKey] = JSON.parse(item.fieldValue)
          } catch (e) {
            msgError(`${item.fieldValue} 不是合法的 json 字符串`)
            return
          }
        } else if (item.fieldType === 'object') {
          try {
            this.value[item.fieldKey] = JSON.parse(item.fieldValue)
          } catch (e) {
            msgError(`${item.fieldValue} 不是合法的 json 字符串`)
            return;
          }
        }
      }
      this.addFields = []
      this.refreshValue()
      this.addFieldFlag = false
    },
    deleteAddField(item) {
      this.$confirm('确认删除 ' + item.fieldKey + ' 字段?', 'warning')
        .then(() => {
          if (Array.isArray(this.addFields)) {
            this.addFields.splice(this.addFields.indexOf(item), 1);
          } else {
            delete this.addFields[item.fieldKey];
          }
          this.$message({
            type: 'success',
            message: `删除 ${item.fieldKey} 字段成功!`
          });
        })
        .catch(() => {
          this.$message({
            type: 'info',
            message: '已取消删除'
          });
        });
    },
    resetBol(field, val) {
      this.value[field] = val
      this.$emit('input', this.value);
    },
    refreshValue() {
      let val = this.value
      this.value = {}
      this.value = val
    }
  },
  mounted() {
    this.hasDataDo()
    this.orderedFieldsDo()
  },
  template: `
<div :class="'json-obj-main-' + depth">
  <!-- 数据 -->
  <div v-for="field in orderedFields" v-if="hasDataFlag">
    <div class="key-value-out">
      <!-- key -->
      <div class="key-value-main">
        <div :class="'key-value-key key-type-' + keyWidth" :title="field">
          {{ field.length > keyWidthSize[4] ? field.substring(0, keyWidthSize[4]) + '...' : field }}
          <el-button type="text" @click="copyValue(field)" size="mini" icon="el-icon-document-copy"></el-button>
        </div>

        <!-- 值展示 -->
        <div class="key-value-value">
          <!-- 字符串 -->
          <input v-model="value[field]" v-if="valInfos[field]['type'] === 'string'"
                 :class="'input-text-' + depth" @change="resetStr(field)" type="text"/>

          <!-- 对象 -->
          <div v-else-if="valInfos[field]['type'] === 'object'">
            <!-- 正常显示 -->
            <div v-if="valInfos[field]['display']">
              <!-- null值 -->
              <span v-if="value[field] === null || value[field] === undefined">
                <input v-model="value[field]" style="width: 60px"/><span style="font-size: 11px;color: gray"> 对象类型，值为null</span>
              </span>
              <json-input ref="child" v-model="value[field]" v-else-if="depth < maxDepth" :depth="depth+1"/>
              <!-- 递归深度超标暂时 -->
              <span v-else title="该数据为对象，超过显示限制">{{ objToStr(value[field]) }}</span>
            </div>
            <div v-else :class="'input-text-' + depth" style="white-space: normal; word-break: break-all">
              <span title="该数据为对象，超过显示限制">{{ objToStr(value[field]) }}</span>
            </div>
          </div>

          <!-- 数字 -->
          <el-input-number v-model="value[field]" v-else-if="valInfos[field]['type'] === 'number'" size="mini"
            style="width: 200px"/>

          <!-- 布尔类型 -->
          <el-radio-group v-model="value[field]" size="mini" @change="resetBol(field, $event)" 
             v-else-if="valInfos[field]['type'] === 'boolean'">
            <el-radio-button :label="true" :key="true"/>
            <el-radio-button :label="false" :key="false"/>
          </el-radio-group>
        </div>

        <!-- 值操作 -->
        <div :class="'key-value-open open-' + (depth > maxDepth? 'open-string-true': valInfos[field]['className'])">
          <el-tooltip :content="field + ' 字段值json对象转json格式字符串'">
            <el-button @click="toStr(field)" type="text" v-if="valInfos[field]['type']  === 'object' || valInfos[field]['type']  === 'number' || valInfos[field]['type']  === 'boolean'"
                       size="mini">
              toStr
            </el-button>
          </el-tooltip>
          
          <el-tooltip v-if="valInfos[field]['type']  === 'number'" :content="field + '时间为：' + dataToStr(value[field])">
            <el-button @click="copyObj(dataToStr(value[field], false))" type="text"
                       size="mini">
              转时间
            </el-button>
          </el-tooltip>

          <span v-if="valInfos[field]['jsonStr'] || depth >= maxDepth">
            <el-tooltip :content="field + ' 字段值json字符串转json'"  v-if="valInfos[field]['jsonStr']">
              <el-button @click="toJson(field)" type="text" size="mini">
                toObj
              </el-button>
            </el-tooltip>
          </span>
            
          <el-tooltip :content="'<' + field + '> 编辑'" v-if="valInfos[field].editFlag">
            <el-button @click="updateStrObj(field)" type="text" icon="el-icon-edit-outline" size="mini"/>
          </el-tooltip>

          <el-tooltip :content="'复制<' + field + '>值（对象时为简化，字符串json保留引号、转义符）'">
            <el-button @click="copyObj(value[field], false)"  type="text" icon="el-icon-document-copy"
                       size="mini"></el-button>
          </el-tooltip>

          <el-tooltip :content="'复制<' + field + '>值为格式化json'"
                      v-if="valInfos[field]['type'] === 'object' || valInfos[field]['jsonStr']">
            <el-button @click="copyObj(value[field], true)"  type="text" icon="el-icon-document-copy"
                       size="mini"></el-button>
          </el-tooltip>

          <span v-if="valInfos[field]['type'] === 'object'">
            <el-tooltip content="将数据改为折叠模式" v-if="valInfos[field]['display']">
              <el-button @click="setDisplay(field, false)" type="text" size="mini" icon="el-icon-folder-opened">
              </el-button>
            </el-tooltip>
              
            <el-tooltip content="将数据改为展开模式" v-if="!valInfos[field]['display']">
              <el-button @click="setDisplay(field, true)" type="text" size="mini" icon="el-icon-folder">
              </el-button>
            </el-tooltip>
          </span>

          <el-tooltip :content="'删除' + field">
            <el-button @click="deleteField(field)" type="text" style="color: red" size="mini" icon="el-icon-delete"></el-button>
          </el-tooltip>
        </div>
      </div>
    </div>
  </div>

  <!-- 无数据 -->
  <div v-if="!hasDataFlag">无数据</div>

  <!-- 增加字段 -->
  <div class="add-key-value-main">
    <!-- 增加按钮 -->
    <el-tooltip :content="(orderedFields.length>0? orderedFields[orderedFields.length-1] + ' 后':'') + '增加'">
      <el-button @click="addField" icon="el-icon-plus" size="mini" circle>
      </el-button>
    </el-tooltip>

    <!-- 增加操作实现 -->
    <div v-if="addFieldFlag">
      <div class="row" v-for="item in addFields">
        <el-input v-model="item.fieldKey" placeholder="请输入字段名称" :class="'key-value-key key-type-' + keyWidth"
                  size="mini"/>

        <el-select v-model="item.fieldType" size="mini" filterable style="width: 90px">
          <el-option value="string" label="String" class="option-div"/>
          <el-option value="number" label="Number" class="option-div"/>
          <el-option value="boolean" label="Boolean" class="option-div"/>
          <el-option value="array" label="Array" class="option-div"/>
          <el-option value="object" label="Object" class="option-div"/>
        </el-select>

        <el-input v-model="item.fieldValue" placeholder="请输入字段值" :class="'input-text-' + depth" size="mini"/>

        <el-button @click="deleteAddField(item)" size="mini" icon="el-icon-delete" type="danger"></el-button>
      </div>

      <el-button type="info" plain @click="addFieldFlag=false" size="mini">取消</el-button>
      <el-button type="primary" @click="addFieldDo" size="mini">添加</el-button>
    </div>
  </div>
  
  <el-dialog :title="dialogTitle" :visible.sync="updateFieldFlag" width="90vw" draggable top="40px">
    <json-input v-model="updateData"/>
    <span slot="footer" class="dialog-footer">
      <el-button @click="updateFieldFlag = false">取 消</el-button>
      <el-button type="primary" @click="updateFieldDo">确 定</el-button>
    </span>
  </el-dialog>
</div>
  `
}
